package server;

import container.Context;
import container.Host;
import container.Mapper;
import container.Wrapper;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Mnicat的主类
 */
public class Bootstrap {

    /** 定义socket监听的端口号 */
    private int port = 8080;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    private Mapper mapper;

    public Mapper getMapper() {
        return mapper;
    }

    public void setMapper(Mapper mapper) {
        this.mapper = mapper;
    }

    /**
     * Minicat启动需要初始化展开的一些操作
     */

    public void start () throws Exception {

        // 初始化配置： 读取配置文件， 并将相关配置信息加载到内存
        Mapper mapper = initConfig();

        int corePoolSize = 10;
        int maximumPoolSize = 20;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.MICROSECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );

        /**
        // 完成Minicat1.0版本
            需求：浏览器请求http://localhost:8080, 返回一个固定的字符串到页面， “hello Minicat“
         */
        ServerSocket serverSocket = new ServerSocket();
        this.port = mapper.getPort();
        serverSocket.bind(new InetSocketAddress(port));

        System.out.println("======>>>>>>>>>Minicat start on port: " + port);

        /*for(;;) {
            Socket accept = serverSocket.accept();
            InputStream inputStream = accept.getInputStream();
            //有了socket， 接收到请求， 回去输出流
            OutputStream outputStream = accept.getOutputStream();
            String content = "hello Minicat";
            String responseText = HttpProtocolUtil.getHttpHeader200(content.getBytes().length)
                    + content;
            outputStream.write(responseText.getBytes());
            outputStream.flush();
            outputStream.close();
            inputStream.close();
            accept.close();
        }*/

        /**
         * 完成Mincat2.0
         * 需求： 封装Request和Response对象， 返回html静态资源文件
         */
       /* while(true) {
            System.out.println("waiting...");
            Socket accept = serverSocket.accept();
            OutputStream outputStream = accept.getOutputStream();

            // 封装Request对象和Response对象
            Request request = new Request(accept.getInputStream());
            Response response = new Response(accept.getOutputStream());

            response.outputHtml(request.getUrl());
            accept.close();
        }*/
       
       /**
        * 完成minicat 3.0
        * 需求：可以请求动态资源
        */
        /*while(true) {
            System.out.println("waiting...");
            Socket accept = serverSocket.accept();
            OutputStream outputStream = accept.getOutputStream();

            // 封装Request对象和Response对象
            Request request = new Request(accept.getInputStream());
            Response response = new Response(accept.getOutputStream());

            if(servletMap.get(request.getUrl()) == null) {
                response.outputHtml(request.getUrl());
            } else {2q
                servletMap.get(request.getUrl()).service(request, response);
            }
            accept.close();
        }*/

        /**
         *  多线程改造， 不使用线程池
         */
        /*while (true) {
            Socket accept = serverSocket.accept();
            RequestProccesor requestProccesor = new RequestProccesor(accept, servletMap);
            new Thread(requestProccesor).start();
        }*/

        /**
         *  多线程改造， 使用线程池
         */
        while (true) {
            Socket accept = serverSocket.accept();

            RequestProccesor requestProccesor = new RequestProccesor(accept, mapper);
//            RequestProccesor requestProccesor = new RequestProccesor(accept, mapper);

            // 分发处理器
            executor.execute(requestProccesor);
        }


    }

    private Mapper initConfig() throws Exception {
        // 读取配置文件
        InputStream resourceAsStream = this.getClass().getResourceAsStream("/server.xml");
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();
        mapper = new Mapper();

        // 读取端口信息
        Element connectorNode = (Element) rootElement.selectSingleNode("//Connector");
        mapper.setPort(Integer.parseInt(connectorNode.attributeValue("port")));

        // 读取主机信息
        List<Element> list = rootElement.selectNodes("//Host");
        for (Element element : list) {
            Host host = new Host();
            String hostName = element.attributeValue("name");
            String appBase = element.attributeValue("appBase");
            host.setName(hostName);
            host.setValue(appBase);

            // 读取并加载主机配置文件， web.xml
            loadServlet(appBase, host);

//            host.getContexts().add()
            mapper.getHosts().add(host);
        }

        return mapper;


    }

    private Map<String, HttpServlet> servletMap = new HashMap<>();

    private void loadServlet(String basePath, Host host) throws Exception {
        String path = basePath + "/web.xml";
        InputStream resourceAsStream = this.getClass().getResourceAsStream(path);

        Context context = host.getContext();

        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();
        List<Element> selectNodes = rootElement.selectNodes("//servlet");
        for (int i = 0; i < selectNodes.size(); i++) {
            Element element = selectNodes.get(i);
            //<servlet-name>demo</servlet-name>
            Node servletNode = element.selectSingleNode("//servlet-name");
            String servletName = servletNode.getStringValue();
            //<servlet-class>server.LagouServlet</servlet-class>
            Node servletClassNode = element.selectSingleNode("//servlet-class");
            String servletClassName = servletClassNode.getStringValue();

            //<servlet-mapping>
            Node servletMappingNodes = rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name = '" + servletName + "']");
            //<url-pattern>/demo</url-pattern>
            Node urlNode = servletMappingNodes.selectSingleNode("//url-pattern");
            String url = urlNode.getStringValue();

//            servletMap.put(url, (HttpServlet) Class.forName(servletClassName).newInstance());
            //
            Wrapper wrapper = new Wrapper();
            wrapper.setName(url);
            wrapper.setValue(Class.forName(servletClassName).newInstance());
            context.getWrappers().add(wrapper);
//
        }

        host.setContext(context);

    }

    /**
     * Minicat 的启动入口
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            // 启动Minicat
            bootstrap.start();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
